﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Threading;

namespace Benchmark
{
    class Program
    {
        const int _fileSize = 5 * 1024 * 1024;
        const int _bufferSize = 2 * 1024;

        static byte[] _emptyData;
        static byte[] _randomData;

        const FileOptions FileFlagNoBuffering = (FileOptions)0x20000000;

        static void Main(string[] args)
        {
            //Profile("new objects", 1000000, NewObjects);

            _emptyData = new byte[_bufferSize];

            Random r = new Random();
            
            _randomData = new byte[_bufferSize];

            r.NextBytes(_randomData);

            //Profile("Write Empty Test File", 100, WriteTestFileWithZeros, ClearTestFiles);
            Profile("Write Random Test File", 200, WriteTestFileWithData, ClearTestFiles);
            Profile("Write Random Test File With Set Length", 200, WriteTestFileWithDataAndSetLength, ClearTestFiles);
            
            Console.WriteLine();

            Console.WriteLine("Finished");

            //Console.ReadKey();
        }

        static void NewObjects(int runs)
        {
            for (int i = 0; i < runs; i++)
            {
                object test = new object();
            }
        }

        static void WriteTestFileWithZeros(int runs)
        {
            for (int i = 0; i < runs; i++)
            {
                using (FileStream s = File.Create(@"d:\bench\test\" + i))
                {
                    for (int written = 0; written < _fileSize; written += _bufferSize)
                        s.Write(_emptyData, 0, _bufferSize);
                }
            }
        }

        static void WriteTestFileWithData(int runs)
        {
            for (int i = 0; i < runs; i++)
            {
                using (FileStream s = File.Create(@"d:\bench\test\" + i))
                {
                    for (int written = 0; written < _fileSize; written += _bufferSize)
                        s.Write(_randomData, 0, _bufferSize);                    
                }
            }
        }

        static void WriteTestFileWithDataAndSetLength(int runs)
        {
            for (int i = 0; i < runs; i++)
            {
                using (FileStream s = File.Create(@"d:\bench\test\" + i, _bufferSize, FileOptions.None))
                {
                    s.SetLength(_fileSize);

                    for (int written = 0; written < _fileSize; written += _bufferSize)
                        s.Write(_randomData, 0, _bufferSize);
                }
            }
        }

        static void ClearTestFiles()
        {
            if (Directory.Exists(@"d:\bench"))
            {
                foreach (string dir in Directory.EnumerateDirectories(@"d:\bench"))
                    Directory.Delete(dir, true);

                //Thread.Sleep(10000);
            }

            Directory.CreateDirectory(@"d:\bench\test");
        }

        static void Profile(string name, int runs, Action<int> benchmark, Action clean = null)
        {
            if (clean != null)
                clean();

            Stopwatch timer = Stopwatch.StartNew();

            benchmark(runs);

            timer.Stop();

            float freq = runs / (timer.ElapsedMilliseconds / 1000f);

            Console.WriteLine("Executed {0} benchmark. Total: {1} ms Runs/s: {2}", name, timer.ElapsedMilliseconds, freq);
        }
    }
}
